package com.itheima.sh.exception;

import com.google.common.collect.ImmutableMap;
import com.itheima.sh.response.ResponseResult;
import com.itheima.sh.response.StatusCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.io.IOException;

/**
 * 拦截 BusinessException 自定义异常
 *
 * @author win10
 */
@RestControllerAdvice
public class ExceptionAdvice {

    private static final Logger log = LoggerFactory.getLogger(ExceptionAdvice.class);

    @ExceptionHandler(BusinessException.class)
    public ResponseResult catchBusinessException(BusinessException e) {
        log.error(e.getMsg(), e);
        return ResponseResult.errorResult(e.getCode(), e.getMsg());
    }

    @ExceptionHandler(IOException.class)
    public ResponseResult catchBusinessException(IOException e) {
        log.error(" IO异常：", e);
        return ResponseResult.errorResult(StatusCode.IO_ERROR.getCode(), StatusCode.IO_ERROR.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ResponseResult catchException(Exception e) {
        // 捕获异常类
        Class<? extends Exception> exClass = e.getClass();
        if (EXCEPTIONS == null) {
            EXCEPTIONS = builder.build();
        }
        // 先到 Map 里面找 异常 有 直接返回
        ResponseResult responseResult = EXCEPTIONS.get(exClass);
        if (responseResult == null) {
            log.error(" 未知异常：", e);
            return ResponseResult.errorResult(StatusCode.ERROR.getCode(), e.toString());
        }
        log.error(" 已分类异常：", e);
        return responseResult;
    }

    /**
     * 拦截的是不可预知的异常
     * 使用EXCEPTIONS存放异常类型和错误代码的映射，ImmutableMap的特点的一旦创建不可改变，并且线程安全
     */
    private static ImmutableMap<Class<? extends Throwable>, ResponseResult> EXCEPTIONS;

    /**
     * 使用builder来构建一个异常类型和错误代码的异常
     */
    protected static ImmutableMap.Builder<Class<? extends Throwable>, ResponseResult> builder = ImmutableMap.builder();

    static {
        // 新增异常类
        builder.put(ArithmeticException.class, ResponseResult.errorResult(StatusCode.ARITHMETIC_ERROR));
        builder.put(NullPointerException.class, ResponseResult.errorResult(StatusCode.ARITHMETIC_ERROR));
    }
}